
package com.hlkj.pay.app.pay.impl;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.common.util.json.JsonUtils;
import com.hlkj.pay.app.pay.IProviderAppService;
import com.hlkj.pay.common.CommonResultCode;
import com.hlkj.pay.common.PayResultCode;
import com.hlkj.pay.dto.merchant.ProviderChannelFeeConfigList;
import com.hlkj.pay.enums.CommonEnum;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.gateway.merchant.IMerchantAccessGateway;
import com.hlkj.pay.infrastructure.model.pay.PayChannelDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelFeeConfigDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderInfoDO;
import com.hlkj.pay.service.common.IBusinessLogService;
import com.hlkj.pay.service.pay.IPayChannelService;
import com.hlkj.pay.service.pay.IProviderService;
import com.hlkj.pay.util.MerchantUtils;
import com.hlkj.pay.vo.pay.req.ProviderChannelConfigReq;
import com.hlkj.pay.vo.pay.req.ProviderChannelFeeConfigReq;
import com.hlkj.pay.vo.pay.req.ProviderInfoReq;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.BeanUtil;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;

/**
 * @author HlpayTeam
 * @date 2024/09/23 16:30
 */
@Service
@RequiredArgsConstructor
@Slf4j
@Validated
public class ProviderAppServiceImpl implements IProviderAppService {

    private final IProviderService providerService;

    private final IPayChannelService payChannelService;
    private final IBusinessLogService businessLogService;
    private final IMerchantAccessGateway merchantAccessGateway;

    @Override
    public CommonResult<String> saveProviderInfo(ProviderInfoReq providerInfoReq) {
        log.info("saveProviderInfo providerInfoReq:{}", JsonUtils.toJsonString(providerInfoReq));
        try {
            // 去掉名称校验
            // ProviderInfoDO providerInfoDO = providerService.queryByName(providerInfoReq.getName());
            // if (providerInfoDO != null) {
            //     return CommonResult.error(PayResultCode.PROVIDER_EXITS);
            // }

            String code = code(1);
            if (!StringUtils.hasText(code)) {
                log.info("saveProviderInfo create code fail providerInfoReq:{}", JsonUtils.toJsonString(providerInfoReq));
                return CommonResult.error(PayResultCode.PROVIDER_CODE_ERROR);
            }
            ProviderInfoDO providerInfoDO = BeanUtil.copy(providerInfoReq, ProviderInfoDO.class);
            providerInfoDO.setCode(code);
            providerService.save(providerInfoDO);
            return CommonResult.success(code);
        }
        catch (Exception e) {
            log.error("saveProviderInfo fail providerInfoReq:{},message:{}", JsonUtils.toJsonString(providerInfoReq), e.getMessage(),e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<Void> updateProviderInfo(ProviderInfoReq providerInfoReq) {
        log.info("updateProviderInfo providerInfoReq:{}", JsonUtils.toJsonString(providerInfoReq));
        try {
            if(!StringUtils.hasText(providerInfoReq.getCode())){
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            ProviderInfoDO providerInfoDb = providerService.queryByCode(providerInfoReq.getCode());
            if (providerInfoDb == null) {
                return CommonResult.error(PayResultCode.PROVIDER_NOT_EXITS);
            }
            // 去掉名称校验
            // ProviderInfoDO providerInfo = providerService.queryByName(providerInfoReq.getName());
            // if (providerInfo != null && !providerInfoDb.getCode().equals(providerInfoReq.getCode())) {
            //     return CommonResult.error(PayResultCode.PROVIDER_EXITS);
            // }
            ProviderInfoDO updateProviderInfo = BeanUtil.copy(providerInfoReq, ProviderInfoDO.class);
            updateProviderInfo.setId(providerInfoDb.getId());
            providerService.update(updateProviderInfo);
            //变更日志
            businessChangeLog(providerInfoDb,updateProviderInfo);
            return CommonResult.success();
        }
        catch (Exception e) {
            log.error("updateProviderInfo fail providerInfoReq:{},message:{}", JsonUtils.toJsonString(providerInfoReq), e.getMessage(),e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<Void> delProviderInfo(String code) {
        log.info("delProviderInfo code:{}", code);
        try {
            if(!StringUtils.hasText(code)){
                return CommonResult.error(CommonResultCode.PARAMETER_MISSING);
            }
            ProviderInfoDO providerInfoDb = providerService.queryByCode(code);
            if (providerInfoDb == null) {
                return CommonResult.error(PayResultCode.PROVIDER_NOT_EXITS);
            }
            providerService.delProviderInfo(code);
            //变更日志
            ProviderInfoDO providerInfoDO=BeanUtil.copy(providerInfoDb,ProviderInfoDO.class);
            providerInfoDO.setDeleteFlag(Boolean.TRUE);
            businessChangeLog(providerInfoDb,providerInfoDO);
            return CommonResult.success();
        }
        catch (Exception e) {
            log.error("delProviderInfo fail code:{},message:{}", code, e.getMessage(),e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<Void> saveConfig(ProviderChannelConfigReq providerChannelConfigReq) {
        log.info("saveConfig providerInfoReq:{}", JsonUtils.toJsonString(providerChannelConfigReq));
        try {
            PayChannelDO payChannelDO = payChannelService.queryByCode(providerChannelConfigReq.getChannelCode());
            if (payChannelDO == null) {
                return CommonResult.error(PayResultCode.PAY_CHANNEL_NOT_EXITS);
            }
            ProviderChannelConfigDO providerChannelConfigDO = new ProviderChannelConfigDO();
            providerChannelConfigDO.setProviderCode(providerChannelConfigReq.getProviderCode());
            providerChannelConfigDO.setChannelCode(providerChannelConfigReq.getChannelCode());
            providerChannelConfigDO.setStatus(providerChannelConfigReq.getStatus());
            providerChannelConfigDO.setParamsConfig(JsonUtils.toJsonPrettyString(providerChannelConfigReq.getParamsConfigValue()));
            providerChannelConfigDO.setWechatMiniId(JsonUtils.toJsonString(providerChannelConfigReq.getWechatMiniIdList()));
            providerChannelConfigDO.setWechatPubId(JsonUtils.toJsonString(providerChannelConfigReq.getWechatPubIdList()));
            providerChannelConfigDO.setAlipayPubId(providerChannelConfigReq.getAlipayPubId());
            providerChannelConfigDO.setAlipayMiniId(providerChannelConfigReq.getAlipayMiniId());
            CommonResult<Void> commonResult = merchantAccessGateway.channelConfigCheck(providerChannelConfigDO);
            if(!commonResult.isSuccess()){
                return commonResult;
            }
            ProviderChannelConfigDO channelConfigDb = providerService.queryConfig(providerChannelConfigReq.getProviderCode(), providerChannelConfigReq.getChannelCode());
            if (channelConfigDb == null) {
                providerService.saveConfig(providerChannelConfigDO);
            }
            else {
                providerChannelConfigDO.setId(channelConfigDb.getId());
                providerService.updateConfig(providerChannelConfigDO);
                //变更日志
                businessChangeLog(channelConfigDb,providerChannelConfigDO);
            }
            return CommonResult.success();
        }
        catch (Exception e) {
            log.error("saveConfig fail providerInfoReq:{},message:{}", JsonUtils.toJsonString(providerChannelConfigReq),  e.getMessage(),e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    @Override
    public CommonResult<Void> saveFeeConfig(@Valid ProviderChannelFeeConfigReq providerChannelFeeConfigReq) {
        log.info("saveFeeConfig providerInfoReq:{}", JsonUtils.toJsonString(providerChannelFeeConfigReq));
        try {
            PayChannelDO payChannelDO = payChannelService.queryByCode(providerChannelFeeConfigReq.getChannelCode());
            if (payChannelDO == null) {
                return CommonResult.error(PayResultCode.PAY_CHANNEL_NOT_EXITS);
            }
            List<String> payWapCodeList = payChannelDO.getPayWapCodeList();
            if(CollectionUtils.isEmpty(payWapCodeList)){
                return CommonResult.error(PayResultCode.PAY_CHANNEL_WAY_NOT_ERROR);
            }
            List<ProviderChannelFeeConfigDO> finalChannelFeeConfigList = new ArrayList<>();
            for (ProviderChannelFeeConfigList providerChannelFeeConfigList : providerChannelFeeConfigReq.getProviderChannelFeeConfigList()) {
                if (!payWapCodeList.contains(providerChannelFeeConfigList.getPayWayCode())) {
                    String format = String.format(PayResultCode.PAY_CHANNEL_WAY_NOT_EXITS.getMsg(),
                            payChannelDO.getName(), providerChannelFeeConfigList.getPayWayCode());
                    return CommonResult.error(PayResultCode.PAY_CHANNEL_WAY_NOT_EXITS.getCode(),format);
                }
                ProviderChannelFeeConfigDO providerChannelFeeConfigDO = new ProviderChannelFeeConfigDO();
                providerChannelFeeConfigDO.setProviderCode(providerChannelFeeConfigReq.getProviderCode());
                providerChannelFeeConfigDO.setChannelCode(providerChannelFeeConfigReq.getChannelCode());
                providerChannelFeeConfigDO.setPayWayCode(providerChannelFeeConfigList.getPayWayCode());
                providerChannelFeeConfigDO.setStatus(providerChannelFeeConfigList.getStatus());
                providerChannelFeeConfigDO.setApplyType(providerChannelFeeConfigList.getApplyType());
                providerChannelFeeConfigDO.setStepFeeType(providerChannelFeeConfigList.getStepFeeType());
                if (!CollectionUtils.isEmpty(providerChannelFeeConfigList.getStepFeeConfigs())) {
                    providerChannelFeeConfigDO.setStepFeeConfig(JsonUtils.toJsonPrettyString(
                            providerChannelFeeConfigList.getStepFeeConfigs()));
                }
                else {
                    // 提交过来有阶梯费率配置 没提交值
                    if (providerChannelFeeConfigList.getStepFeeType().equals(CommonEnum.YES_NO_TYPE.YES.getCode())) {
                        return CommonResult.error(PayResultCode.STEP_FEE_NOT_EXITS);
                    }
                }
                providerChannelFeeConfigDO.setSeniorFeeType(providerChannelFeeConfigList.getSeniorFeeType());
                if (providerChannelFeeConfigList.getSeniorFeeConfigValue() != null) {
                    providerChannelFeeConfigDO.setSeniorFeeConfig(JsonUtils.toJsonPrettyString(
                            providerChannelFeeConfigList.getSeniorFeeConfigValue()));
                }
                else {
                    // 提交过来有高级费率配置 没提交值
                    if (providerChannelFeeConfigList.getSeniorFeeType().equals(CommonEnum.YES_NO_TYPE.YES.getCode())) {
                        return CommonResult.error(PayResultCode.SENIOR_FEE_NOT_EXITS);
                    }
                }
                if (providerChannelFeeConfigList.getDefaultFeeConfigValue() != null) {
                    providerChannelFeeConfigDO.setDefaultFeeConfig(JsonUtils.toJsonPrettyString(
                            providerChannelFeeConfigList.getDefaultFeeConfigValue()));
                }
                else {
                    // 提交过来有没有阶梯费率配置、高级费率配置 没提交默认费率配置
                    if (providerChannelFeeConfigList.getSeniorFeeType().equals(CommonEnum.YES_NO_TYPE.NO.getCode())
                            && providerChannelFeeConfigList.getStepFeeType().equals(CommonEnum.YES_NO_TYPE.NO.getCode())) {
                        return CommonResult.error(PayResultCode.DEFAULT_FEE_NOT_EXITS);
                    }
                }
                finalChannelFeeConfigList.add(providerChannelFeeConfigDO);
            }
            List<ProviderChannelFeeConfigDO> channelFeeConfigList = providerService.queryFeeConfig(providerChannelFeeConfigReq.getProviderCode(),
                    providerChannelFeeConfigReq.getChannelCode());
            if (!CollectionUtils.isEmpty(channelFeeConfigList)) {
                providerService.delFeeConfig(providerChannelFeeConfigReq.getProviderCode(), providerChannelFeeConfigReq.getChannelCode());
            }
            providerService.batchSaveFeeConfig(finalChannelFeeConfigList);
            if (!CollectionUtils.isEmpty(channelFeeConfigList)) {
                //变更日志
                businessChangeLog(channelFeeConfigList,channelFeeConfigList);
            }
            return CommonResult.success();
        }
        catch (Exception e) {
            e.printStackTrace();
            log.error("saveFeeConfig fail providerInfoReq:{},message:{}", JsonUtils.toJsonString(providerChannelFeeConfigReq), e.getMessage(),e);
            return CommonResult.error(CommonResultCode.SERVICE_ERROR);
        }
    }

    String code(int num) {
        if (num > 100) {
            return "";
        }
        String code = MerchantUtils.code("S", 10);
        ProviderInfoDO providerInfoDO = providerService.queryByCode(code);
        if (providerInfoDO != null) {
            return code(num + 1);
        }
        return code;
    }
    /**
     * log object
     * @param beforeProviderInfoDO
     * @param afterProviderInfoDO
     * @return
     */
    void businessChangeLog(ProviderInfoDO beforeProviderInfoDO, ProviderInfoDO afterProviderInfoDO) {
        businessLogService
                .addBusinessChangeLog(beforeProviderInfoDO.getCode(), PayEnums.CHANGE_LOG_TYPE.PROVIDER_INFO.getCode(), CommonEnum.CHANGE_LOG_MODEL_TYPE.PAY,  beforeProviderInfoDO, afterProviderInfoDO);
    }
    /**
     * log object
     * @param beforePayChannel
     * @param afterPayChannel
     * @return
     */
    void businessChangeLog(ProviderChannelConfigDO beforePayChannel, ProviderChannelConfigDO afterPayChannel) {
        businessLogService
                .addBusinessChangeLog(beforePayChannel.getProviderCode()+"_"+beforePayChannel.getChannelCode(), PayEnums.CHANGE_LOG_TYPE.PROVIDER_CONFIG.getCode(), CommonEnum.CHANGE_LOG_MODEL_TYPE.PAY,  beforePayChannel, afterPayChannel);
    }
    /**
     * log object
     * @param beforePayChannel
     * @param afterPayChannel
     * @return
     */
    void businessChangeLog(List<ProviderChannelFeeConfigDO> beforePayChannel, List<ProviderChannelFeeConfigDO> afterPayChannel) {
        businessLogService
                .addBusinessChangeLog(beforePayChannel.get(0).getProviderCode()+"_"+beforePayChannel.get(0).getChannelCode(), PayEnums.CHANGE_LOG_TYPE.PROVIDER_FEE.getCode(), CommonEnum.CHANGE_LOG_MODEL_TYPE.PAY,  beforePayChannel, afterPayChannel);
    }
}
